<!--
 * @Descripttion: 
 * @Author: yuxi
 * @Date: 2022-09-15 14:58:04
 * @LastEditors: yuxi
 * @LastEditTime: 2023-01-17 08:36:31
-->
<template>
  <div class="map-container">
    <MiningMap
      :center="center"
      :zoom="zoom"
      :useContextMenu="true"
      :customContextMenus="customContextMenus"
    >
      <MiningTiandituLayer
        layerName="基础底图"
        :ak="key"
        @ready="ready"
        layerType="img_w"
      ></MiningTiandituLayer>
      <MiningVectorLayer
        :featureStyle="style"
        v-for="(layer, li) in layers"
        :key="layer.layerId"
        :layerName="layer.layerName"
        :layerId="layer.layerId"
        :properties="layer"
        @ready="reloadLayerControl"
      >
        <MiningLineString
          v-for="feature in groupFeatures[layer.layerId]"
          :key="feature.get('properties').id"
          :feature="feature"
        ></MiningLineString>

        <!-- <MiningPolygon
          v-for="feature in groupPolygonFeatures[layer.layerId]"
          :key="feature.get('properties').id"
          :feature="feature"
        ></MiningPolygon> -->
      </MiningVectorLayer>

      <MiningLayerControl ref="layerControl">
        <template #layer="{ layer, layer_index, properties }">
          <MiningLayerControlItem :layer="layer">
            <template #addon>
              <div>
                <!-- <i class="el-icon-edit"></i> -->
                <i
                  v-if="layer_index > 0 && !properties.isLock"
                  class="el-icon-lock"
                  @click="startEdit(layer)"
                  style="margin-right: 5px"
                ></i>
                <i
                  v-if="layer_index > 0 && properties.isLock"
                  class="el-icon-unlock"
                  @click="endEdit(layer)"
                  style="margin-right: 5px"
                ></i>
                <i
                  v-if="layer_index > 0"
                  class="el-icon-delete"
                  @click="removeLayer(layer)"
                ></i>
              </div>
            </template>
          </MiningLayerControlItem>
        </template>
        <template #extend>
          <div class="add-btn">
            <el-button size="small" @click="handleAddLayer">添加图层</el-button>
          </div>
        </template>
      </MiningLayerControl>

      <MiningStyleControl
        v-if="editStyle"
        :defaultStyle="editStyle"
        @submit="endEditStyle"
      ></MiningStyleControl>
    </MiningMap>
  </div>
</template>

<script>
import MiningMap from 'mining-map/Map'
import MiningTiandituLayer from 'mining-map/Layers/TiandituLayer'
import { TiandituKey } from '@/config/config.js';
import { Draw,  Snap, Select, Modify } from 'ol/interaction';
import {Circle as CircleStyle, Fill, Stroke, Style, Stroke as StrokeStyle, Fill as FillStyle,Icon} from 'ol/style';
import {Vector as VectorSource} from 'ol/source';
import {  Vector as VectorLayer} from 'ol/layer';
import { pointerMove } from 'ol/events/condition';
import MiningLayerControl from 'mining-map/Control/LayerControl';
import MiningLayerControlItem from 'mining-map/Control/LayerControlItem';
import MiningVectorLayer from 'mining-map/Layers/VectorLayer'
import MiningPoint from 'mining-map/Features/Point';
import MiningLineString from 'mining-map/Features/LineString';
import MiningPolygon from 'mining-map/Features/Polygon';

import MiningStyleControl from 'mining-map/Control/StyleControl';
import { MiningStyle } from 'mining-map/Style';

import marker from '@/assets/images/marker.png'
import {findAndCountAll, createOne, deleteOne, updateOne} from '@/apis/attr'

import {createOne as createGeo, findAndCountAll as findAllGeos, updateOne as updateGeo} from '@/apis/geo'

import GeoJSON from 'ol/format/GeoJSON';
import Feature from 'ol/Feature';
import Polygon from 'ol/geom/Polygon';
import LineString from 'ol/geom/LineString';
import Point from 'ol/geom/Point';
import Collection from 'ol/Collection';

import { lineToPolygon, lineString, polygonize } from '@turf/turf'

const baseStyle = {
  stroke: {
    color: 'blue',
    lineDash: [4],
    width: 3,
  },
  fill: {
    color: 'rgba(0, 0, 255, 0.1)',
  },
  image: {
    anchor: [0.5, 46],
    anchorXUnits: 'fraction',
    anchorYUnits: 'pixels',
    src: marker,
  }
}

const source = new VectorSource();
const vector = new VectorLayer({
  name: 'AddLayer',
  source: source,
  style: new Style({
    fill: new Fill({
      color: 'rgba(255, 255, 255, 0.2)',
    }),
    stroke: new Stroke({
      color: 'transparent',
      width: 2,
    }),
    image: new CircleStyle({
      radius: 7,
      fill: new Fill({
        color: '#ffcc33',
      }),
    }),
  }),
});

const edit_source = new VectorSource();
const edit_vector = new VectorLayer({
  name: 'RoleLin',
  source: edit_source,
  style: new Style({
    fill: new Fill({
      color: 'rgba(255, 255, 255, 0.2)',
    }),
    stroke: new Stroke({
      // color: 'transparent',
      color: 'red',
      width: 2,
    }),
    image: new CircleStyle({
      radius: 7,
      fill: new Fill({
        color: '#ffcc33',
      }),
    }),
  }),
});
export default {
  name: 'RoadLine',
  title: '道路线图层',
  parentTitle: '业务组件',
  components: {
    MiningMap,
    MiningTiandituLayer,
    MiningLayerControl,
    MiningLayerControlItem,
    MiningVectorLayer,
    MiningLineString,
    MiningStyleControl,
    MiningPolygon
    // MiningPoint
  },
  data () {
    const style = new Style({
      stroke: new StrokeStyle({
        color: 'blue',
        lineDash: [10],
        width: 3,
      }),
      fill: new FillStyle({
        color: 'rgba(0, 0, 255, 0.1)',
      }),
      image: new Icon({
        anchor: [0.5, 46],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: marker,
      })
    })
    return {
      center: [116.43396401346438,39.926523711148874],
      zoom: 17,
      key: TiandituKey,
      draw: null,
      snap: null,
      select: null,
      modify: null,
      layers: [],
      style,
      map: null,
      features: [],
      activeFeature: null,
      editing: false,
      editStyle: null,
      styleEditing: true,
      polygons: []
    }
  },
  created() {
    this.fetchLayers()
  },
  computed:{
    editLayer () {
      return this.layers.find(l => {
        return l.isLock
      })
    },
    groupFeatures () {
      let groups = {}
      this.features.map(f => {
        let properties = f.get('properties')
        groups[properties.layer_id]= groups[properties.layer_id] || []
        groups[properties.layer_id].push(f)
      })
      if(this.editLayer) {
        groups[this.editLayer.layerId] = []
      }

      return groups
    },
    groupPolygonFeatures () {
      let groups = {}
      this.polygons.map(f => {
        let properties = f.get('properties')
        groups[properties.layer_id]= groups[properties.layer_id] || []
        groups[properties.layer_id].push(f)
      })
      if(this.editLayer) {
        groups[this.editLayer.layerId] = []
      }

      return groups
    },
    customContextMenus () {
      if(this.editing) {
        return this.activeFeature ? [{
        name: '结束编辑',
        handler: () => {
          this.editFeatuerEdit()
        }
      }]:[]
      } else {
        return this.activeFeature ? [{
        name: '编辑要素',
        handler: () => {
          this.startFeatureEdit()
        }
      },{
        name: '编辑样式',
        handler: this.startEditStyle
      }]:[]
      }
      
    }
  },
  watch: {
    editLayer () {
      if(this.editLayer) {
        this.actionStart()
      } else {
        this.actionEnd()
      }
    },
    groupFeatures () {
      console.log('groupFeatures', this.groupFeatures)
    }
  },
  methods: {
    ready ({ map }) {
      this.map = map
      this.map.on('pointermove', this.mouseMove)
      // this.addInteractions(map) 
    },
    mouseMove (evt) {
      if(this.editing) {
        return
      }
      let active = this.map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
        return {
          feature: feature,
          layer: layer
        };
      }, {
        hitTolerance: 10
      });
      // console.log(feature);
      if (active) {
        this.activeFeature = active
        this.activeFeature.feature.setStyle(new Style({
          stroke: new StrokeStyle({
            color: 'red',
            width: 4,
          }),
        }))
      } else if(this.activeFeature) {
        // this.activeFeature.feature.setStyle(this.style)
        this.resetFeatureStyle(this.activeFeature.feature)
        this.activeFeature = null
      }
    },
    resetFeatureStyle(feature) {
      console.log('resetFeatureStyle')
      let properties = feature.get('properties')
      let style = properties.style
      if(style) {
        let s = new MiningStyle()
        s.fromJSON(JSON.parse(style))
        feature.setStyle(s)
      } else {
        feature.setStyle(this.style)
      }
    }, 
    fetchLayers () {
      findAndCountAll({
        table: 'layer_info',
        page:1,
        pageSize: 100
      }).then(res => { 
        if(res.code === 0) {
          this.layers = res.data.rows.filter(r => {
            return !r.geom
          })
          .map(r => {
            return {
              layerId: r.id,
              layerName: r.name,
              type: 'vectorLayer',
              isLock: r.isLock
            }
          })
          this.findAllGeos()
          this.$nextTick(() => {
            this.reloadLayerControl()
          })
        }
      })
    },
    findAllGeos () {
      this.polygons = []
      source.refresh()
      findAllGeos({
        table: 'line',
        page:1,
        pageSize: 100
      }).then(res => { 
        if(res.code === 0) {
          this.features = res.data.rows.map(r => {
            console.log(r.geom)
            var line = lineString(r.geom.coordinates);

            var polygon = polygonize(line);

            console.log(polygon)
            let polygonFeature = new Feature({
              type: 'Polygon',
              geometry: new GeoJSON().readGeometry(polygon.geometry),
              name: r.id + '_polygon', 
              properties: {
                id: r.id,
                layer_id: r.layer_id,
                style: r.style
              }
            })
            this.polygons.push(polygonFeature)
            let style = null
            if(r.style) {
              style = new MiningStyle()
              style.fromJSON(JSON.parse(r.style))
            } 
            let f= new Feature({
              type: 'LineString',
              geometry: new GeoJSON().readGeometry(r.geom),
              name: r.id,
              style: style || undefined,
              properties: {
                id: r.id,
                layer_id: r.layer_id,
                style: r.style
              }
            })
            if(style) {
              f.setStyle(style)
            }
            return f
          })
          source.addFeatures(this.features) 
          // edit_source.addFeatures(this.features) 
          if(this.editLayer) {
            let edit_features = this.features.filter(f => {
              return f.get('properties').layer_id === this.editLayer.layerId
            })
            console.log('edit_features', edit_features, this.features)
            edit_source.clear()
            edit_source.addFeatures(edit_features)
          }
        }
      })
      
    },
    actionStart() {
      this.addInteractions(this.map)
    },
    actionEnd() {
      if(!this.draw) {
        return
      }
      console.log('actionEnd')
      edit_source.clear()
      this.map.un('contextmenu', this.stopDraw) 
      this.map.removeLayer(vector) 
      this.map.removeLayer(edit_vector) 

      this.map.removeInteraction(this.draw);
      this.draw.setActive(false)
      this.map.removeInteraction(this.modify);

    },
    addInteractions (map) {
      console.log(this.editLayer.layerId)
      let edit_features = this.features.filter(f => {
        return f.get('properties').layer_id === this.editLayer.layerId
      })
      console.log('edit_features', edit_features, this.features)
      edit_source.clear()
      edit_source.addFeatures(edit_features)


      if(this.draw) {
        map.on('contextmenu', this.stopDraw)  
        map.addLayer(vector)
        map.addLayer(edit_vector)

        map.addInteraction(this.draw); 
        map.addInteraction(this.modify);
        this.draw.setActive(true)

        return
      }
      map.on('contextmenu', this.stopDraw)  
      map.addLayer(vector)
      map.addLayer(edit_vector)
      // edit_source.addFeatures(this.features)

      this.draw = new Draw({
        source: source,
        type: 'LineString',
      });

      this.modify = new Modify({source: edit_source});
      this.draw.on('drawend', this.handleDrawEnd)
      this.modify.on('modifyend', this.handleModifyEnd)

      // this.draw.on('drawstart', this.handleDrawStart) 
      // this.snap = new Snap({ source: source });

      // this.select = new Select({
      //   layers: [vector],
      //   hitTolerance: 10,
      //   condition: pointerMove
      // })
      // this.select.on('select', this.handleSelect)

      // map.addInteraction(this.select);
      map.addInteraction(this.draw);
      map.addInteraction(this.modify);

      // map.addInteraction(this.snap);

    },
    stopDraw () {
      console.log(this.draw)
      if(this.draw.getActive()) {
        this.draw.finishDrawing()
      }
    },
    handleDrawEnd (evt) {
      const {feature} = evt 
      const featureGeoJSON = new GeoJSON().writeFeatureObject(feature)
      
      createGeo({
        table: 'line',
        geom: featureGeoJSON.geometry,
        layer_id: this.editLayer.layerId
      }).then(res  => {
        if(res.code === 0) {
          let {data} = res
          let newfeature = new Feature({
              type: 'LineString',
              geometry: new GeoJSON().readGeometry(data.geom),
              name: data.id,
              properties: {
                id: data.id,
                layer_id: data.layer_id
              }
          })
          this.features.push(newfeature)
          // this.findAllGeos()
          edit_source.removeFeature(feature)
          edit_source.addFeature(newfeature)

          
        }
      }).finally(() => {
        // source.refresh()
      })
    },
    handleModifyEnd (evt) {
      console.log(evt.features.getLength())
      let feature = evt.features.item(0)
      
      console.log(feature)
      this._updateLine(feature)
      // console.log(evt)

    },
    _updateLine(feature) {
      const featureGeoJSON = new GeoJSON().writeFeatureObject(feature)
      console.log(featureGeoJSON)
      updateGeo({
        table: 'line',
        geom: featureGeoJSON.geometry,
        layer_id: featureGeoJSON.properties.properties.layer_id,
        id: featureGeoJSON.properties.properties.id,
        style: featureGeoJSON.properties.properties.style,
      }).then(res  => {
        if(res.code === 0) {
          // this.features.push(new Feature({
          //     type: 'LineString',
          //     geometry: new GeoJSON().readGeometry(data.geom),
          //     name: data.id,
          //     properties: {
          //       id: data.id,
          //       layer_id: data.layer_id
          //     }
          // }))
          // this.findAllGeos()
        }
      }).finally(() => {
        // source.refresh()
      })
    },

    handleDrawStart (evt) {
      console.log(evt)
      evt.stopPropagation()
      evt.preventDefault();
      // this.draw.abortDrawing()
      return false
    },
    handleSelect (evt) {
      console.log(evt)
      this.draw.finishDrawing()
      this.draw.setActive(false)
    },
    handleAddLayer () {
      // this.layers.push({
      //   layerId: 'layer_' + (this.layers.length + 1),
      //   layerName: '图层' + (this.layers.length + 1),
      //   type: 'vectorLayer'
      // })
      let layerName = '图层' + (this.layers.length)
      createOne({
        table: 'layer_info',
        name:  layerName,
        order: this.layers.length
      }).then(res => {
        this.fetchLayers()
        this.$message.success(`${layerName}添加成功`);

      })
    },
    reloadLayerControl () {
      this.$refs.layerControl.load() 
    },
    removeLayer (layer) {
      console.log(layer.get('layerId'))
      let layerId = layer.get('layerId')
      let layerName = layer.get('layerName')

      this.$confirm('是否确认删除当前图层?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          deleteOne({
            table: 'layer_info',
            id: layerId
          }).then(res => {
            if(res.code === 0) {
              this.fetchLayers()
              this.$message.success(`${layerName}删除成功`);

            }
          })
        })
    },
    startEdit (layer) {
      console.log(layer)
      if(!layer) {
        layer = this.activeFeature.layer
      }
      let layerId = layer.get('layerId')
      let layerName = layer.get('layerName')
      this.$message(`${layerName}开启绘制！`);
      this.editing = true

      updateOne(
        {
          table: 'layer_info',
          id: layerId,
          isLock: true
        }
      ).then(() => {
        this.fetchLayers()
      })
    },
    endEdit (layer) {
      let layerId = layer.get('layerId')
      let layerName = layer.get('layerName')
      this.$message(`${layerName}结束绘制！`);
      updateOne(
        {
          table: 'layer_info',
          id: layerId,
          isLock: false
        }
      ).then(() => {
        this.fetchLayers()
      })
      this.editing = false
    },
    startFeatureEdit () {
      let feature = this.activeFeature.feature
      let collection = new Collection([feature])
      if(this.modify) {
        this.modify = new Modify({features: collection});

      }  else {
        this.modify = new Modify({features: collection});
        this.modify.on('modifyend', this.handleModifyEnd) 
      }
      this.map.addInteraction(this.modify);
      this.editing = true

     
    },
    editFeatuerEdit () {
      this.map.removeInteraction(this.modify);
      this.editing = false
      this.activeFeature.feature.setStyle(this.style)
      this.activeFeature = null
      console.log(this.activeFeature)
    },
    startEditStyle () {
      let feature = this.activeFeature.feature
      let properties = feature.get('properties')
      this.editing  =true
      if(properties.style) {
        this.editStyle = JSON.parse(properties.style)
      } else {
        this.editStyle = JSON.parse(JSON.stringify(baseStyle))
      }
    },
    endEditStyle (style) {
      console.log(style)
      let _style = new Style({
        stroke: new StrokeStyle({
          ...style.stroke
        }),
      })
      let properties = this.activeFeature.feature.get('properties')
      properties.style = JSON.stringify(style)
      this.activeFeature.feature.set('properties', properties)
      this.activeFeature.feature.setStyle(_style)
      this._updateLine(this.activeFeature.feature)
      this.editing  =false
      this.editStyle = null

    }, 

  }

}
</script>

<style lang="less">
body,
html {
  padding: 0;
  margin: 0;
}

.map-container {
  width: 100%;
  height: 100vh;
  text-align: left;
  .add-btn {
    padding: 20px;
    text-align: center;
  }
}
</style>